#ifndef XG_MEMQUEUE_H
#define XG_MEMQUEUE_H
////////////////////////////////////////////////////////
#include "Sharemem.h"
#include "Semaphore.h"

#pragma pack(1)

class MemQueue
{
	struct Head
	{
		u_int32 str;
		u_int32 end;
		u_int32 len;
		u_int32 tail;
		u_int32 bottom;
		u_char data[1];
	};

	struct Node
	{
		u_int32 size;
		u_char data[1];

		u_int32 memsize() const
		{
			return sizeof(u_int32) + size;
		}
		u_int32 offset(Head* head) const
		{
			return (u_char*)(&size) - head->data;
		}
		void init(const void* msg, u_int32 len)
		{
			memcpy(data, msg, size = len);
		}
	};

protected:
	Head* head = NULL;

	Node* back()
	{
		return (Node*)(head->data + head->end);
	}
	Node* front()
	{
		return (Node*)(head->data + head->str);
	}

public:
	SmartBuffer pop();
	u_char* pop(u_int32& len);
	bool push(const void* data, u_int32 len);
	bool create(void* buffer, u_int32 maxsz);

	void clear()
	{
		head->str = 0;
		head->end = 0;
		head->len = 0;
		head->bottom = head->tail;
	}
	bool empty() const
	{
		return head == NULL || head->str == head->end;
	}
	u_int32 size() const
	{
		return head ? head->len : 0;
	}
	u_int32 memsize() const
	{
		return head ? head->tail + sizeof(Head) : 0;
	}
	bool open(void* buffer)
	{
		head = (Head*)(buffer);

		return head->str < head->tail && head->end < head->tail;
	}
	template<class DATA_TYPE> bool push(const DATA_TYPE& data)
	{
		return push(&data, sizeof(DATA_TYPE)) >= 0;
	}
	static SmartBuffer MallocBuffer(u_int32 count, u_int32 memsz)
	{
		return sizeof(Head) + count * sizeof(Node) + sizeof(Node) + memsz - count;
	}
};

#pragma pack()

class MsgQueue : public Object
{
protected:
	string name;
	MemQueue mq;
	Sharemem shm;
	Semaphore sem;

public:
	~MsgQueue();
	bool clear();
	void close();
	bool open(const string& name);
	bool create(const string& name, u_int32 len);

	SmartBuffer pop();
	bool push(SmartBuffer data);
	bool pop(void* data, u_int32& len);
	bool push(const void* data, u_int32 len);
	bool pop(SmartBuffer& data, u_int32& len);

	bool empty() const
	{
		return mq.empty();
	}
	bool canUse() const
	{
		return shm.canUse();
	}
	u_int32 size() const
	{
		return mq.size();
	}
	u_int32 memsize() const
	{
		return mq.memsize();
	}
	const string& getName() const
	{
		return name;
	}
};
////////////////////////////////////////////////////////
#endif